/*
 *  Copyright 2013 National Institute of Advanced Industrial Science and Technology
 *  
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *  
 *      http://www.apache.org/licenses/LICENSE-2.0
 *  
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

package org.sss.client;

import java.net.InetSocketAddress;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;

import org.slf4j.Logger;
import org.sss.mapreduce.SssException;

/**
 * Checker whether remote process is alive or not.
 *
 * NOTE: This class is used by only this module.
 */
class KeepAliveTimer {
  private static Logger logger = SssClient.getLogger(KeepAliveTimer.class);
  private static Timer timer = new Timer(true);
  private TimerTask task = null;
  private ClusterManager clusterManager;

  public KeepAliveTimer(ClusterManager cm) {
    this.clusterManager = cm;
  }

  /**
   * Start to check whether remote private is alive or not.
   *
   * @param period interval to send message to check.
   */
  public void start(long period) {
    if (period > 0) {
      task = new KeepAliveTask();
      timer.schedule(task, period * 1000, period * 1000);
    }
  }

  /**
   * Stop to check whether remote private is alive or not.
   */
  public void stop() {
    if (task != null) {
      task.cancel();
      task = null;
    }
  }

  private void notifyKeepAliveError(InetSocketAddress address, Throwable e) {
    logger.error("Keep alive error" + ((address != null)?(" in " + address):""), e);
    clusterManager.notifyKeepAliveError(e);
  }

  private class KeepAliveTask extends TimerTask {
    @Override
    public void run() {
      try {
        logger.debug("Check whether server is alive or not.");
        for (Map.Entry<InetSocketAddress, ClusterManager.Server> entry: clusterManager.getServerMap().entrySet()) {
          // When another call, skip
          ClusterManager.Server server = entry.getValue();
          if (server.tryLock()) {
            try {
              server.get().aliveCheck();
            } catch (Throwable e) { // Catch all error.
              notifyKeepAliveError(entry.getKey(), e);
            } finally {
              server.unlock();
            }
          }
        }
      } catch (SssException e) {
        notifyKeepAliveError(null, e);
      }
    }
  }
}
